Angular路由之间共享数据时如何避免Observable的痛苦?
How to avoid the pain of Observable when sharing data between routes in Angular?
当我们希望在路由之间共享数据时,唯一可行的解决方案似乎是使用服务。由于我们希望数据在更新时在视图中重新呈现,因此我们必须使用 BehaviorSubject
.
所以,如果我错了,请纠正我,但一个简单的组件将如下所示:
@Component({
selector: 'user-info',
template: `
{{($user | async).firstName}}
<button (click)="updateName()"></button>
`
})
export class UserInfoComponent {
private $user;
private subscribe;
constructor(private service: UserService) {
this.user$ = this.service.get();
}
updateName() {
this.subscribe = this.service.get().subscribe(user =>
this.service.update({...user, firstName: 'new-name'})
);
}
ngOnDestroy() {
this.subscribe.unsubscribe();
}
}
这听起来真的很令人沮丧,因为如果我们不使用路由器,我们可以只使用 <user-info [user]="user | async"></user-info>
调用组件,这样会更干净:
@Component({
selector: 'user-info',
template: `
{{user.lastName}}
<button (click)="updateName()"></button>
`
})
export class UserInfo2Component {
@Input() user: User;
constructor(private service: UserService) {}
updateName() {
this.service.update({...user, lastName: 'new-name'});
}
}
所以我的问题是:为什么在路由之间共享数据如此困难?有没有我可能错过的更好的解决方案?
您可以使用 ngrx
来避免使用可观察对象。它基于 redux
概念。
通过这种方式,您可以将数据设置到商店,在您的路线中传递一些 id,并在下一个路线中使用该 id 从商店获取数据。现在,store 是这里唯一的数据源,你不需要在路由之间传递数据,每个路由都可以将数据设置到 store,其他路由可以从 store 访问它。
在此处阅读更多相关信息:为什么使用 NGRX 而不是使用可观察对象的构造函数注入服务?
你的错误是在组件中处理更新逻辑,而不是在服务中。
尝试这样的事情:
user.service
import { Component, Input } from '@angular/core';
import {BehaviorSubject} from 'rxjs/BehaviorSubject';
export class UserService {
private user = new BehaviorSubject({
firstName: 'Tomasz'
})
user$ = this.user.asObservable();
update(user: any) {
this.user.next({
...this.user.getValue(),
...user
})
}
}
app.component.ts
import { Component } from '@angular/core';
import {UserService} from './user.service';
@Component({
selector: 'my-app',
template: `
<input (keydown.enter)="updateUser(input.value); input.value=''" #input>
{{ user$ | async | json }}
`,
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
user$;
constructor(private userService: UserService) {
this.user$ = this.userService.user$;
}
updateUser(firstName: string) {
this.userService.update({ firstName });
}
}
当我们希望在路由之间共享数据时,唯一可行的解决方案似乎是使用服务。由于我们希望数据在更新时在视图中重新呈现,因此我们必须使用 BehaviorSubject
.
所以,如果我错了,请纠正我,但一个简单的组件将如下所示:
@Component({
selector: 'user-info',
template: `
{{($user | async).firstName}}
<button (click)="updateName()"></button>
`
})
export class UserInfoComponent {
private $user;
private subscribe;
constructor(private service: UserService) {
this.user$ = this.service.get();
}
updateName() {
this.subscribe = this.service.get().subscribe(user =>
this.service.update({...user, firstName: 'new-name'})
);
}
ngOnDestroy() {
this.subscribe.unsubscribe();
}
}
这听起来真的很令人沮丧,因为如果我们不使用路由器,我们可以只使用 <user-info [user]="user | async"></user-info>
调用组件,这样会更干净:
@Component({
selector: 'user-info',
template: `
{{user.lastName}}
<button (click)="updateName()"></button>
`
})
export class UserInfo2Component {
@Input() user: User;
constructor(private service: UserService) {}
updateName() {
this.service.update({...user, lastName: 'new-name'});
}
}
所以我的问题是:为什么在路由之间共享数据如此困难?有没有我可能错过的更好的解决方案?
您可以使用 ngrx
来避免使用可观察对象。它基于 redux
概念。
通过这种方式,您可以将数据设置到商店,在您的路线中传递一些 id,并在下一个路线中使用该 id 从商店获取数据。现在,store 是这里唯一的数据源,你不需要在路由之间传递数据,每个路由都可以将数据设置到 store,其他路由可以从 store 访问它。
在此处阅读更多相关信息:为什么使用 NGRX 而不是使用可观察对象的构造函数注入服务?
你的错误是在组件中处理更新逻辑,而不是在服务中。
尝试这样的事情:
user.service
import { Component, Input } from '@angular/core';
import {BehaviorSubject} from 'rxjs/BehaviorSubject';
export class UserService {
private user = new BehaviorSubject({
firstName: 'Tomasz'
})
user$ = this.user.asObservable();
update(user: any) {
this.user.next({
...this.user.getValue(),
...user
})
}
}
app.component.ts
import { Component } from '@angular/core';
import {UserService} from './user.service';
@Component({
selector: 'my-app',
template: `
<input (keydown.enter)="updateUser(input.value); input.value=''" #input>
{{ user$ | async | json }}
`,
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
user$;
constructor(private userService: UserService) {
this.user$ = this.userService.user$;
}
updateUser(firstName: string) {
this.userService.update({ firstName });
}
}